<?php
class Index{
	const indexCountKey=5;

	
	private $shmIndex;
	private $shmSystem;
	private $semShmSystem;
	const bufferCount=1000000;
	//const bufferCount=5;
	function __construct($shmIndex,$shmSystem,$semShmSystem,$clear=false) {
		$this->shmIndex=$shmIndex;
		$this->shmSystem=$shmSystem;
		$this->semShmSystem=$semShmSystem;
		if ($clear)
			$this->count(null);
	}

	function shiftMemoryDown($index){
		$count=$this->count();
		$maxI=intval(floor(($count-$index-1)/self::bufferCount));
		for($i=$maxI;$i>=0;$i--){
			if($i==$maxI)
				$delta=(($count-$index-1)%self::bufferCount)+1;
			else
				$delta=self::bufferCount;
				var_dump('delta',$i,$index+$i*self::bufferCount,$delta);
			$res=shmop_read($this->shmIndex,($index+$i*self::bufferCount)*8,($delta)*8);		
			shmop_write($this->shmIndex,$res,($index+$i*self::bufferCount+1)*8);
		}
	}


	function shiftMemoryUp($index){
		$count=$this->count();
		$maxI=intval(floor(($count-$index)/self::bufferCount));
		//var_dump($count,$index,$maxI);
		for($i=0;$i<=$maxI;$i++){
			var_dump('i',$i);
			if($i==$maxI){
				$delta=(($count-$index-2)%self::bufferCount)+1;
				//var_dump($delta);
			}
			else
				$delta=self::bufferCount;
				//var_dump('start',($index+$i*self::bufferCount+1)*8,($delta)*8);
			$res=shmop_read($this->shmIndex,($index+$i*self::bufferCount+1)*8,($delta)*8);	
			//var_dump('start');
			shmop_write($this->shmIndex,$res,($index+$i*self::bufferCount)*8);
			//var_dump('end');
		}
	}

	function delete($key){
		$res=$this->searchIndex($key,false);
		$count=$this->count();
		if($res[1]===1 and $res[0]<($count-1)){
			echo 'start';
			$this->shiftMemoryUp($res[0]);
			echo 'end';
		}
		if($res[1]===1)
			$this->count(-1);	
	}
	function set($key,$value){
		$res=$this->searchIndex($key,false);
//		var_dump('index',$key,$res);
		$count=$this->count();
		if($res[1]===0 and $res[0]<$count){
			$this->shiftMemoryDown($res[0]);
		}
		if($res[1]===0)
			$this->count(1);		
		shmop_write($this->shmIndex,pack('i',$key).pack('i',$value),$res[0]*8);
	}
	function count($n=false){
			$c=false;
			sem_acquire($this->semShmSystem);
			if($n===null){
				shm_put_var($this->shmSystem,self::indexCountKey,0);
				$c=true;
			}
			else{
				$c=shm_get_var($this->shmSystem,self::indexCountKey);
				if($n!==false){
					$c=$c+$n;
					shm_put_var($this->shmSystem,self::indexCountKey,$c);
				}
			}	
			sem_release($this->semShmSystem);		
			return $c;					
		}
	function searchIndex($key,$strict=true){
		$first=0;
		$count=$this->count();
		$last=$count;
		while ($first < $last){
			$mid = $first + intval(($last - $first) / 2);
	 
			if ($key <= $this->getIndex($mid)){
				$last = $mid;
			}
			else{
				$first = $mid + 1;
			}
		}
		if ($count!=0 && $this->getIndex($last) == $key && $last<$count){
			if($strict)
				return $last;
			else
				return Array($last,1);
		} else{
			if($strict)
				return false;
			else
				return Array($last,0);
		}
	}
	
	function getIndex($i){
		$res=shmop_read($this->shmIndex,$i*8,4);
		$res=unpack('ikey',$res);
		return $res['key'];
	}
	function get($key){
		
		$offset=$this->searchIndex($key,true);
		//var_dump('get',$key,$offset);
		if($offset===false)
			return false;
			//var_dump($offset);
		$res=shmop_read($this->shmIndex,$offset*8+4,4);
		$res=unpack('iaddr',$res);
		return ($res['addr']);
	}	
}

?>